package com.ask.service.businessService;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.ask.dto.Result;
import com.ask.dto.UserDTO;
import com.ask.threadlocals.UserHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class demoService {
    @Autowired
    private IBlogService blogService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private IUserService userService;

    /**
     * 博客点赞
     *
     * @param id
     * @return
     */
    public Result likeBlog(Long id) {

        // 获取当前用户
        Long userId = UserHolder.getUser().getId();
        // 当前用户是否点赞过？
        String key = "blog:like" + id;
        Double score = stringRedisTemplate.opsForZSet().score(key, userId);
        if (score == null) { // 未点赞过
            // 跟新数据库
            boolean success = blogService.update().setSql("like = like + 1").eq("id", id).update();
            // 跟新redis
            if (success)
                stringRedisTemplate.opsForZSet().add(key, userId.toString(), System.currentTimeMillis());
        } else { // 点赞过
            // 跟新数据库
            boolean success = blogService.update().setSql("like = like - 1").eq("id", id).update();
            if (success)
                stringRedisTemplate.opsForZSet().remove(key, userId.toString());
        }
        return Result.success();
    }

    /**
     * Lua脚本解决并发问题
     *
     * @param blogId
     * @return
     */
    public Result likeBlog_V2(Long blogId) {
        String script =
                "local key = KEYS[1];" +
                        "local userId = ARGV[1];" +
                        "local timestamp = ARGV[2];" +
                        "local exists = redis.call('ZSCORE', key, userId);" +
                        "if (not exists) then" +
                        "  redis.call('ZADD', key, timestamp, userId);" +
                        "  return 1;" +
                        "else" +
                        "  redis.call('ZREM', key, userId);" +
                        "  return 0;" +
                        "end";
        String key = "blog:like" + blogId;
        Long userId = UserHolder.getUser().getId();

        // 指向lua脚本
        Long result = stringRedisTemplate.execute(
                new DefaultRedisScript<>(script, Long.class),
                Collections.singletonList(key),
                userId.toString(),
                String.valueOf(System.currentTimeMillis())
        );

        if (result == 1) {
            boolean success = blogService.update()
                    .setSql("like = like + 1").
                    eq("id", blogId).update();
        } else
            blogService.update().setSql("like = like - 1").eq("id", blogId).update();
        return Result.success();
    }

    /**
     * 当前用户是否点赞过当前博客
     *
     * @param blogId
     * @return
     */
    public boolean isLiked(Long blogId) {
        Long userId = UserHolder.getUser().getId();
        String key = "blog:like" + blogId;
        Double score = stringRedisTemplate.opsForZSet().score(key, userId);
        return score != null;
    }


    /**
     * 查询博客的点赞排行榜
     *
     * @param blogId
     * @return
     */
    public Result queryBlogLikes(Long blogId) {
        String key = "blog:like" + blogId;
        Set<String> idsSet = stringRedisTemplate.opsForZSet().range(key, 0, 4);
        if (idsSet == null || idsSet.isEmpty())
            return Result.success(Collections.emptyList());
        // 查询点赞的用户信息
        List<Long> ids = idsSet.stream().map(Long::valueOf).collect(Collectors.toList());
        String idsStr = StrUtil.join(",", ids);
        List<UserDTO> userDTOList = userService.query()
                .in("id", ids).last("order by field(id," + idsStr + ")").list()
                .stream().map(user -> BeanUtil.copyProperties(user, UserDTO.class))
                .collect(Collectors.toList());
        return Result.success(userDTOList);
    }
}
